package validator

import (
	"bytes"
	"crypto/sha256"
	"errors"
	"github.com/wanchain/go-mpc/common"
	"github.com/wanchain/go-mpc/common/hexutil"
	"github.com/wanchain/go-mpc/log"
	"github.com/wanchain/go-mpc/storeman/osmconf"
	mpcprotocol "github.com/wanchain/go-mpc/storeman/storemanmpc/protocol"
	"math/big"
	"strings"
)

func IsMalice(grpId string, smInx uint16) (bool, error) {

	mc, err := maliceCount(grpId, smInx)
	if err != nil {
		return false, err
	}
	log.SyslogInfo("IsMalice", "grpId", grpId, "smIndx", smInx, "maliceCount", mc)
	if mc >= uint8(mpcprotocol.MaxMalice) {
		return true, nil
	}
	return false, nil
}

func BuildKey(grpId string, smInx uint16) common.Hash {
	var buf bytes.Buffer
	grpItem, _ := osmconf.GetOsmConf().GetGrpItem(grpId, smInx)
	buf.Write((*grpItem.NodeId)[:])
	return sha256.Sum256(buf.Bytes())
}

func maliceCount(grpId string, smInx uint16) (uint8, error) {
	sdb, err := GetDB()
	if err != nil {
		log.SyslogErr("MaliceCount, getting storeman database fail", "err", err.Error())
		return 0, mpcprotocol.ErrGetDb
	}

	key := BuildKey(grpId, smInx)
	value, err := sdb.Get(key[:])
	if err != nil {
		//ValidateData, sdb.Get has fail           err=leveldb: not found
		if strings.Contains(err.Error(), "leveldb") && strings.Contains(err.Error(), "not found") {
			//err=leveldb: not found
			// not output to log
		} else {
			log.SyslogErr("maliceCount, sdb.Get has fail", "err", err.Error())
		}
		return 0, errors.New("get MaliceCount error")
	}

	log.SyslogInfo("maliceCount", "grpId", grpId, "index", smInx, "count", uint8(big.NewInt(0).SetBytes(value).Uint64()))
	log.SyslogInfo("maliceCount", "enodeId", hexutil.Encode(key[:]), "maliceCount", value)

	return uint8(big.NewInt(0).SetBytes(value).Uint64()), nil
}

func SetMaliceCount(grpId string, smInx uint16, maliceCount uint8) error {
	sdb, err := GetDB()
	if err != nil {
		log.SyslogErr("SetMaliceCount, getting storeman database fail", "err", err.Error())
		return mpcprotocol.ErrGetDb
	}

	key := BuildKey(grpId, smInx)
	value := big.NewInt(0).SetUint64(uint64(maliceCount))
	log.SyslogInfo("SetMaliceCount", "enodeId", hexutil.Encode(key[:]), "maliceCount", value)
	return sdb.Put(key[:], value.Bytes())
}

//func IncMaliceCount(grpId string, smInx uint16) error {
//	mc, err := maliceCount(grpId, smInx)
//	if err != nil {
//		return err
//	}
//	mc += 1
//
//	return SetMaliceCount(grpId, smInx, mc)
//}

func IncMaliceCount(grpId string, smInx uint16) error {
	mc, _ := maliceCount(grpId, smInx)
	mc += 1
	return SetMaliceCount(grpId, smInx, mc)
}

func GetMalicIndex(bsender bool, sndInx, rcvIndx uint16) uint16 {
	if bsender {
		return sndInx
	} else {
		return rcvIndx
	}
}
